#include "comthread.h"
#include <QSerialPortInfo>
#include <QDebug>
#include <QApplication>
#include "my_crc.h"

/* mSerial : 串口
 * RecvTimer : 接收定时器，串口接收数据后触发数据接收
 * RecvTime  : 延时N ms后接收数据
 * RespTimer : 等待响应定时器，200ms/次的判断(第一次1s)，共计6次
 * RespStu   : 等待响应状态，判断设备是否无响应
 */
ComThread::ComThread(QObject *parent) : QThread(parent)
{
    mSerial    = new QSerialPort;
    RecvTimer  = new QTimer;
    RecvTime   = 200;
    RespTimer  = new QTimer;
    RespStu    = WAIT_STU_WAIT;
    WaitTimer  = new QTimer;
    RecvTimeOut = 0;
    // 读取数据
    connect(mSerial,&QSerialPort::readyRead,this,&ComThread::SerialPort_Read_Start);
    connect(RecvTimer,&QTimer::timeout,this,&ComThread::ReceviceSerialData);
    connect(RespTimer,&QTimer::timeout,this,&ComThread::RespTimer_TimeOut);
    connect(WaitTimer,&QTimer::timeout,this,&ComThread::WaitTimer_TimeOut);
}

QStringList ComThread::GetSerialAvailable()
{
    QStringList mPortsList;

    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        mPortsList << info.portName();
    }
    return mPortsList;
}

bool ComThread::InitSerial(QString portname)
{
    // 设置端口部分参数
    mSerial->setBaudRate(QSerialPort::Baud115200);
    mSerial->setDataBits(QSerialPort::Data8);
    mSerial->setParity(QSerialPort::NoParity);
    mSerial->setStopBits(QSerialPort::OneStop);
    mSerial->setPortName(portname);
    if(!mSerial->open(QIODevice::ReadWrite))
    {
        qDebug()<<"Serial port opening failed";
        return false;
    }
    qDebug()<<"Serial port open successfully";

    return true;
}

void ComThread::CloseSerial()
{
    if(WaitTimer->isActive())
    {
        WaitTimer->stop();
    }
    if(RespTimer->isActive())
    {
        RespTimer->stop();
    }
    if(RecvTimer->isActive())
    {
        RecvTimer->stop();
    }
    if(mSerial->isOpen())
    {
        mSerial->clear();
        mSerial->close();
    }
    qDebug()<<"Serial port closed successfully";
}

//数据接收:触发中断->延时后接收数据
void ComThread::SerialPort_Read_Start()
{
    if(!RecvTimer->isActive())
    {
        RecvTimer->start(RecvTime);
    }
}

void ComThread::ReceviceSerialData()
{
    RecvTimer->stop();

    QByteArray buffer;
    buffer.clear();
    buffer.append(mSerial->readAll());
    if(myserial_Cmd_Check(buffer))
    {
        RespStu = WAIT_STU_DATA;
        emit UpdateSerialData(buffer);
    }
}

/* 超时处理
 *
 */
void ComThread::RespTimer_TimeOut()
{
    RespStu = WAIT_STU_OUT;
}
bool ComThread::RecvData_TimeOut(QByteArray data)
{
    int OutCnt = 0;
    int TimeStart = 1000;
    int TimeOut = 1000;
    int TimeCnt = 0;
    if(RecvTimeOut > TimeOut)
    {
        TimeOut = RecvTimeOut;
    }
    LastCmd = data;
    do
    {
        mSerial->write(data);
        if(!RecvTimer->isActive())
        {
            RespStu = WAIT_STU_WAIT;
        }
        RespTimer->start(TimeStart);
        while(WAIT_STU_WAIT == RespStu)QCoreApplication::processEvents();
        RespTimer->stop();
        TimeCnt += TimeStart;
        if((WAIT_STU_OUT == RespStu) && (TimeOut == TimeCnt))
        {
            OutCnt++;
            TimeStart = 500;
            TimeOut = 500;
            TimeCnt = 0;
        }
        else
        {
            return true;
        }
    }while(5 > OutCnt);

    data.clear();
    data.append("timeout");
    emit UpdateSerialData(data);

    return false;
}

/* 同步定时器
 * 每隔5秒发送一次同步指令
 */
void ComThread::WaitTimer_TimeStart()
{
    WaitTimer->start(5000);
}
void ComThread::WaitTimer_TimeStop()
{
    WaitTimer->stop();
}
bool ComThread::WaitTimer_TimeActive()
{
    return WaitTimer->isActive();
}
void ComThread::WaitTimer_TimeOut()
{
    // 或许应该加一个限制条件，确保同步指令在其它命令结束后发出
    SendSerial_LinkCmd_Wait();
}

/* 延时时间初始化
 * 根据数据长度 初始化 接收数据前的延时时间
 */
void ComThread::RecvTime_Init(long DataSize)
{
    long SendTime = DataSize*90;// 115200波特率的每个字节发送时间约为90us

    RecvTime = SendTime/1000;   // 余数省去，因为后续间隔只多不少
    RecvTime = 20 + RecvTime*2; // 20:发送接收间隔,随数据量增大而增大

    RecvTimeOut = RecvTime;
}

void ComThread::SendSerialData(QByteArray data)
{
    RecvTime_Init(data.size());
    // 接收GUI数据并发送
    mSerial->write(data);
}
QByteArray UsbCmd_HEAD_Compose(uint8_t CmdStu, uint16_t DataSize)
{
    QByteArray CmdBuff;
    // Head
    CmdBuff.clear();
    CmdBuff.append(USB_PAGE_HEAD);
    // Cmd
    QByteArray CmdStr;
    CmdStr.clear();
    CmdStr.append(CmdStu);                  //code
    CmdStr.append((DataSize >> 0) & 0xFF);  //size.lsb
    CmdStr.append((DataSize >> 8) & 0xFF);  //size.msb
    CmdBuff.append("    ");
    CmdBuff[9] = myserial_EccCalc(CmdStr);
    CmdBuff[6] = CmdStr[0]; //code
    CmdBuff[7] = CmdStr[1]; //size.lsb
    CmdBuff[8] = CmdStr[2]; //size.msb
    return CmdBuff;
}
QByteArray UsbCmd_CMD_Compose(uint8_t CmdStu, QByteArray DataBuff, uint16_t DataSize)
{
    QByteArray CmdBuff;
    // Head
    CmdBuff.clear();
    CmdBuff.append(UsbCmd_HEAD_Compose(CmdStu, DataSize));

    // Data
    DataBuff.append(2, char(0));
    myserial_CmdCrc(DataBuff, DataSize);
    CmdBuff.append(DataBuff);

    return CmdBuff;
}
// 连接指令集
void ComThread::SendSerial_LinkCmd_Link()   // 连接
{
    QByteArray data;
    data.clear();
    data.append(UsbCmd_HEAD_Compose(USB_PAGE_LINK, 0));
    //
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void ComThread::SendSerial_LinkCmd_Wait()   //同步
{
    QByteArray data;
    data.append(UsbCmd_HEAD_Compose(USB_PAGE_SYNC, 0));
    //
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void ComThread::SendSerial_LinkCmd_Break()  //断开
{
    QByteArray data;
    data.append(UsbCmd_HEAD_Compose(USB_PAGE_BREAK, 0));
    //
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void ComThread::SendSerial_LinkCmd_Repeat()  //重发
{
    QByteArray data;
    data.append(UsbCmd_HEAD_Compose(USB_PAGE_REPEAT, 0));
    //
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void ComThread::RecvSerial_LinkCmd_Repeat()  //接收重发
{
    RecvData_TimeOut(LastCmd);
}

// DL400 原彩数据指令集
void ComThread::SendSerial_MtsnCmd_SendCode(QByteArray code, uint16_t addr)
{
    //判断盖板码长度
    if(code.size() != 44)
    {
        QByteArray ErrStr;
        ErrStr.clear();
        ErrStr.append("警告:盖板码长度为");
        ErrStr.append(QString::number(code.size(), 10));
        emit UpdateSerialData(ErrStr);
        return;
    }
    //
    code.insert(0, ((addr>>8)&0x000000FF));
    code.insert(1, ((addr>>0)&0x000000FF));
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(UsbCmd_CMD_Compose(USB_PAGE_BURN_MTSN, code, code.size()));
    //
    RecvTime_Init(cmd.size());
    RecvTimeOut = 60000;
    //
    RecvData_TimeOut(cmd);
}
void ComThread::SendSerial_MtsnCmd_RecvCode(QByteArray code, uint16_t addr)
{
    //
    code.clear();
    code.insert(0, ((addr>>8)&0x000000FF));
    code.insert(1, ((addr>>0)&0x000000FF));
    QByteArray cmd;
    cmd.clear();
    cmd.append(UsbCmd_CMD_Compose(USB_PAGE_READ_MTSN, code, code.size()));
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
void ComThread::SendSerial_MtsnCmd_SendData(QByteArray data, uint16_t addr)
{
    //
    data.insert(0, ((addr>>8)&0x000000FF));
    data.insert(1, ((addr>>0)&0x000000FF));
    QByteArray cmd;
    cmd.clear();
    cmd.append(UsbCmd_CMD_Compose(USB_PAGE_BURN_DATA, data, data.size()));
    //
    RecvTime_Init(2048);
    RecvTimeOut = 60000;
    //
    RecvData_TimeOut(cmd);
}
void ComThread::SendSerial_MtsnCmd_RecvData(QByteArray data, uint16_t addr)
{
    //
    data.clear();
    data.insert(0, ((addr>>8)&0x000000FF));
    data.insert(1, ((addr>>0)&0x000000FF));
    QByteArray cmd;
    cmd.clear();
    cmd.append(UsbCmd_CMD_Compose(USB_PAGE_READ_DATA, data, data.size()));
    //
    RecvTime_Init(2048);
    RecvTimeOut = 60000;
    //
    RecvData_TimeOut(cmd);
}
